﻿using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using QDT.Common;
using QDT.Common.Plugins;
using QDT.Core;
using QDT.Core.Domain;
using QDT.Core.Members;
using QDT.Core.Orders;
using QDT.Core.Payments;
using QDT.P2B.Domain.Config;
using QDT.P2B.Domain.Messages;

namespace QDT.Services.Payments {
    public class PaymentService : ServiceBase, IPaymentService {
        #region Implementation of IPaymentService

        /// <summary>
        /// 获得系统所有的支付方式接口
        /// </summary>
        /// <returns></returns>
        public ICollection<IPayment> GetPayments() {
            var paymentManager = new PaymentManager();

            IList<IPayment> payments = paymentManager.LoadPlugins();

            return payments;
        }

        /// <summary>
        /// 取得所有有效的支付方式
        /// </summary>
        /// <returns></returns>
        public ICollection<IPayment> GetEffectPayments() {
            IQueryable<PaymentInfo> paymentInfos = DbProvider.D<PaymentInfo>().Where(x => x.IsEffect).OrderByDescending(x=>x.Sort);

            var paymentManager = new PaymentManager();

            var result = new List<IPayment>();

            foreach (PaymentInfo paymentInfo in paymentInfos) {
                IPayment payment = paymentManager.GetPlugins(paymentInfo.ClassName);

                if (payment == null) continue;

                payment.Logo = paymentInfo.Logo;
                payment.Sort = paymentInfo.Sort;
                payment.FeeType = paymentInfo.FeeType;
                payment.FeeAmount = paymentInfo.FeeAmount;
                payment.Config = paymentInfo.Config;

                result.Add(payment);
            }

            return result;
        }

        /// <summary>
        /// 安装支付接口
        /// </summary>
        /// <param name="payment"></param>
        public void Install(IPayment payment) {

            Check.Argument.IsNotNull(payment, "payment");

            if(DbProvider.D<PaymentInfo>().Count(x=>x.ClassName==payment.Key)>0) throw new ApplicationException("{0} 已经安装.".FormatWith(payment.Name));

            var paymentInfo = new PaymentInfo();

            PaymentToInfo(payment, paymentInfo);

            DbProvider.Add(paymentInfo);
            DbProvider.SaveChanges();
        }

        /// <summary>
        /// 更新支付接口配置
        /// </summary>
        /// <param name="payment"></param>
        public void Update(IPayment payment) {

            Check.Argument.IsNotNull(payment, "payment");

            var paymentInfo = DbProvider.D<PaymentInfo>().FirstOrDefault(x=>x.ClassName==payment.Key);

            if (paymentInfo == null) return;

            PaymentToInfo(payment, paymentInfo);

            DbProvider.SaveChanges();
        }

        /// <summary>
        /// 卸载支付接口
        /// </summary>
        /// <param name="paymentInfoID">接口的安装信息ID</param>
        public void Uninstall(int paymentInfoID) {
            var paymentInfo = DbProvider.GetByID<PaymentInfo>(paymentInfoID);

            if (paymentInfo == null) return;

            DbProvider.Delete(paymentInfo);

            DbProvider.SaveChanges();
        }


        /// <summary>
        /// 根据支付接口的安装ID获得支付插件
        /// </summary>
        /// <param name="paymentInfoId"></param>
        /// <returns></returns>
        public IPayment GetPayment(int paymentInfoId) {
            var paymentInfo = DbProvider.GetByID<PaymentInfo>(paymentInfoId);

            if (paymentInfo == null) return null;

            var paymentManager = new PaymentManager();

            IPayment payment = paymentManager.GetPlugins(paymentInfo.ClassName);

            if (payment == null) return null;

            InfoToPayment(paymentInfo, payment);

            return payment;
        }

        private static  object _asnyLock = new object();

        /// <summary>
        /// 根据支付接口的Key,获得支付接口
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public IPayment GetPayment(string key) {

            lock (_asnyLock)
            {
                var paymentInfo = DbProvider.D<PaymentInfo>().FirstOrDefault(x => x.ClassName == key);

                if (paymentInfo == null) return null;

                var paymentManager = new PaymentManager();

                IPayment payment = paymentManager.GetPlugins(paymentInfo.ClassName);

                if (payment == null) return null;

                InfoToPayment(paymentInfo, payment);

                return payment;
            }
            
        }

        private void PaymentToInfo(IPayment payment,PaymentInfo info) {
            info.ClassName = payment.Key;
            info.Config = payment.Config;
            info.Description = payment.Description;
            info.FeeAmount = payment.FeeAmount;
            info.FeeType = payment.FeeType;
            info.IsEffect = payment.IsEffect;
            info.Logo = payment.Logo;
            info.Name = payment.Name;
            info.OnlinePay = payment.OnlinePaly;
            info.Sort = payment.Sort;
        }

        private void InfoToPayment(PaymentInfo info,IPayment payment) {

            payment.Logo = info.Logo;
            payment.Sort = info.Sort;
            payment.FeeType = info.FeeType;
            payment.FeeAmount = info.FeeAmount;
            payment.Config = info.Config;
            payment.Description = info.Description;
            payment.IsEffect = info.IsEffect;

            payment.Finished += payment_Finished;
            payment.NotifyVerifyFaild += payment_NotifyVerifyFaild;
        }


        /// <summary>
        /// 支付认证失败
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void payment_NotifyVerifyFaild(object sender, EventArgs e) {
            
            var po = sender as PaymentOrder;

            var notice = DbProvider.D<PaymentNotice>().FirstOrDefault(x => x.NoticeSn == po.PaymentNo);

            if (notice == null) return;

            notice.Memo = "第三方支付失败："+ po.Description;
            notice.IsPaid = false;

            var order = DbProvider.GetByID<ChargeOrder>(notice.OrderId);

            if (order == null) return;

            order.Status=ChargeOrderStatus.Failure;
            order.Memo = "支付出错";
            order.UpdateTime = DateTime.Now;

            order.Add("系统", "订单状态改变,第三方支付失败");

            DbProvider.SaveChanges();

        }

        /// <summary>
        /// 支付完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void payment_Finished(object sender, EventArgs e) {

            var po = sender as PaymentOrder;

            var notice = DbProvider.D<PaymentNotice>().FirstOrDefault(x => x.NoticeSn == po.PaymentNo && ! x.IsPaid );

            if (notice == null) return;

            notice.Memo = "支付成功";

            notice.IsPaid = true;

            notice.PayTime = DateTime.Now;

            var order = DbProvider.GetByID<ChargeOrder>(notice.OrderId);

            if (order == null) return;

            //以处理过订单，不再处理，避免管理员处理过后，第三方才返回通知，重复充值
            if (order.Status == ChargeOrderStatus.Completed) return;

            order.Status = ChargeOrderStatus.Completed;
            order.PayAmount = po.Money;
            order.UpdateTime = DateTime.Now;

            order.Add("系统","通过第三方支付成功");

            var user = DbProvider.GetByID<User>(order.UserID);
            
            var info = "充值订单{0},通过{1}方式支付成功[{2}]".FormatWith(po.PaymentNo, po.Description, notice.NoticeSn);
            var userlog=user.Transaction(UserTransLog.TradeType.Charge, order.PayAmount, "", info);

            DbProvider.Add(userlog);

            if (SettingManager.Get<MessageConfig>().SmsOpen && user.MobilePassed)
            {
                var msg = new MsgQueueFactory().CreateInchargeMsg(user.Mobile, order.PayAmount, order.OrderSN);
                DbProvider.Add(msg);
            }

            DbProvider.SaveChanges();
        }

        #endregion
    }
}